package com.sencorsta.ids.game.world.pak;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sencorsta.ids.common.service.MsgService;
import com.sencorsta.ids.common.service.MysqlService;
import com.sencorsta.ids.common.service.RedisService;
import com.sencorsta.ids.core.log.Out;
import com.sencorsta.ids.core.tcp.socket.protocol.RpcMessage;
import com.sencorsta.ids.game.db.RpMassage;
import com.sencorsta.ids.game.db.SettlementResult;
import com.sencorsta.ids.game.db.Wallet;
import com.sencorsta.ids.game.proto.GamePushRedPackageByProto;
import com.sencorsta.ids.game.proto.GamePushRobMoneyByProto;
import com.sencorsta.ids.game.util.MoneyPiece;
import com.sencorsta.ids.game.util.PacketMoney;
import com.sencorsta.ids.game.world.bean.Player;
import com.sencorsta.ids.game.world.bean.World;
import com.sencorsta.ids.game.world.room.JinQiangRoom;
import com.sencorsta.utils.date.DateUtil;
import com.sencorsta.utils.templet.Weights;

import java.util.*;

import static com.sencorsta.ids.game.util.PushAndSaved.pushProto;

/**
 * @author TAO
 * @description: 禁枪玩法
 * @date 2019/11/19 22:41
 */
public class JinQiangPackage extends RedPackage implements RedisService {

    public List<Integer> thunderNumber;//雷号集合

    public int redType = 0;//5 单包 55；连环包  666 六不中

    public int mediumMineNumber = 0;//中雷数

    public Map<Integer, Double> magnification;//当前包赔率

    public double currentMagnification;//当前包赔率

    public JinQiangRoom jinQiangRoom;

    public JinQiangPackage(String sendUserId, String rpId, int count, long amount, JinQiangRoom jinQiangRoom, List<Integer> thunderNumber, int redType,boolean isRobotPack) {
        super(sendUserId, rpId, count, amount, computeRobDeposit(amount, count, jinQiangRoom, redType), jinQiangRoom.roomId,isRobotPack);
        this.thunderNumber = thunderNumber;
        //this.moneyPieces = PacketMoney.getPacketMoney(PacketMoney.getRandomWeightsList(amount, count),amount, count, 1);//得到分配金额+雷号
        this.magnification = jinQiangRoom.getCurrentMagnification(jinQiangRoom, redType);//得到当前包的赔率列表
        this.redType = redType;
        this.jinQiangRoom = jinQiangRoom;

        analysis();
    }

    //得到抢红包的人的押金multiplyingPower
    public static long computeRobDeposit(long amount, int count, JinQiangRoom jinQiangRoom, int radType) {
        //总金额 * 最高赔率 /count
        long robDeposit = (long) (amount * jinQiangRoom.getMagnification(radType) / count);
        return robDeposit;//为押金赋值
    }


    public void update() {
        this.time -= 1;//当前包的时间减1秒
        if (status==0){
            if (time == 0 ) {//当前包的死期已到，他妈的干掉
                if (rpResult == null) {//红包结算记录为空，代表没人参与
                    Out.debug("当前包无人问津，自动撤回");
                    status = 2;
                    Settlement();//结算
                    return;
                }
                Out.debug("当前包的死期已到，开始清算结果");
                status = 1;
                Settlement();//结算
                return;
            }
            if (count == 0) {//红包抢完了
                status = 1;
                Settlement();//结算
                return;
            }
        }

    }

    @Override
    public void analysis() {
        //判断是否是机器人发包
        boolean isMustWin = World.getInstance().isMustWinbyRoom(roomId);
        int[] weight=new int[]{256,128};
        if (isRobotPack) {//机器人发包
            //机器人发包时 人类必中雷 机器人随便抢
            if (isMustWin) {
                isRobotRobMustWin = true;
                //增加出雷概率
                weight=new int[]{16,256,128,64,32,16,8,4,2};
            }
        } else {//玩家发包
            if (isMustWin) {
                //玩家发包时 如果必赢 机器人只抢赢钱的包
                isRobotRobMustWin = true;
                weight=new int[]{256};
            }

        }
        Weights weights=new Weights(weight);
        Set<Integer> numberSelect=new HashSet<>();
        thunderNumber.forEach((e)->{
            numberSelect.add(e);
        });
        this.moneyPieces = PacketMoney.getListAtboomMut(amount, count, weights.getRandom(),numberSelect,1,redType);

        for (int i = 0; i < moneyPieces.size(); i++) {
            MoneyPiece jsonObject = moneyPieces.get(i);
            long jMoney = jsonObject.getMoney();
            int jThunderNumber = jsonObject.getThunderNumber();
            int temp = 10000000;
            if (redType == 666) {
                for (var item : thunderNumber) {
                    if (jThunderNumber != item) {
                        temp *= -1;
                        break;
                    }
                }
            } else {
                for (var item : thunderNumber) {
                    if (jThunderNumber == item) {
                        temp *= -1;
                        break;
                    }
                }
            }
            int jScore = (int) (jMoney + temp);
            moneyPieces.get(i).setScore(jScore);
        }

        for (int j = 0; j < moneyPieces.size(); j++) {
            if (moneyPieces.get(j).getScore() > 0) {
                moneyPieces.get(j).setWin(true);
            } else {
                moneyPieces.get(j).setWin(false);
            }
        }
    }


    //抢红包
    public void rob(Player player) {
        Out.debug("-----------禁抢抢红包--update-----------");
        if (count == 0 || status != 0) {//判断红包数量
            Out.debug("红包已抢完");
            return;
        }
        if (rpResult.containsKey(player.userId)) {
            Out.debug("该红包你以领取过");
            return;
        }
        playerMap.put(player.userId, player);

        Long robAmount;//抢到的红包金额
        int thunderNumber;//雷数

        //不加控制默认
        int index = getNextIndex();
        if (!isRobotPack && player.type == 2 && isRobotRobMustWin) {
            index = getWinIndex();
            if (index < 0) {
                //没有可以用的包了
                return;
            }
        }
        if (isRobotPack&&player.type == 1&&isRobotRobMustWin){
            index = getLoseIndex();
            if (index < 0) {
                //没有可以用的包了
                index=getNextIndex();
            }
        }


        robAmount = moneyPieces.get(index).getMoney();//直接将剩余红包金额给最后一个人
        thunderNumber = moneyPieces.get(index).getThunderNumber();
        moneyPieces.get(index).setRobed(true);


        //将抢的红包和用户对应起来
        JSONObject result = new JSONObject();
        result.put("robUserId", player.userId);
        result.put("amount", robAmount);
        result.put("thunderNumber", thunderNumber);
        result.put("time", DateUtil.getDateTime());
        result.put("nickname", player.nickname);
        result.put("portrait", player.portrait);
        rpResult.put(player.userId, result);


        balance = balance - robAmount;

        //冻结抢包者的最高赔款金额 --防止在抢到红包到结算期间去抢其他红包（最终导致这里的包在结算时余额不够）
        //TODO--冻结抢包资金----------------------------------------------------------------------------
        player.onRob(rpId, -robDeposit, robDeposit);

        //推送抢到的金额
        GamePushRobMoneyByProto.PushRobMoney.Builder push = GamePushRobMoneyByProto.PushRobMoney.newBuilder();
        push.setGameId(World.JINGQIANG);
        push.setRoomId(roomId);
        push.setRpId(rpId);
        push.setMoney(robAmount);
        Out.debug("禁抢即将为==》", player.userId, "__推送__");


        //MsgService.pushOnlyOnline(pushProto(player.userId, "push.RobMoney", push));

        MsgService.pushBySID(pushProto(player.userId, "push.RobMoney", push),player.SID);


        if (!moneyRecode.containsKey(player.userId)) {//参与抢包用户添加recode的--防止报空
            JSONObject recode = new JSONObject();
            moneyRecode.put(player.userId, recode);
        }
        count = count - 1;
    }


    public void Settlement() {
        try {
            Out.debug("------------------------禁抢包----rpResult----------------------------");
            List<Integer> thunderNumber = this.thunderNumber;//得到雷号集合
            Map<String, Integer> info = new HashMap<>();//中雷情况


            //不管输赢  把抢的钱给玩家加回去
            for (var userId : rpResult.keySet()) {
                JSONObject userRobInfo = (JSONObject) rpResult.get(userId);//得到的userId的结算记录
                int leisureThunderNumber = userRobInfo.getInteger("thunderNumber");//得到当前用户的雷
                long leisureAmount = userRobInfo.getLong("amount");//得到当前用户抢到的钱


                Out.debug("--------不管输赢  把抢的钱给玩家加回去--开始---------用户-------", userId, "------金额-------", leisureAmount);
                JSONObject recod = moneyRecode.getJSONObject(userId);//得到当前玩家的账单记录
                recod.put("robMoney", leisureAmount);//将抢到的钱存到当前玩家的账单记录

                //将中雷者添加到中雷情况集合中
                if (thunderNumber.contains(leisureThunderNumber)) {
                    info.put(userId, leisureThunderNumber);
                }
            }


            this.mediumMineNumber = info.keySet().size();//中雷个数
            Out.debug("中雷数-----》", this.mediumMineNumber);
            long transportAmount = 0;//单个人赔付金额
            int sgin = 0;//中雷标识   0.没人中  1六不中   2.单/连雷中  3.中了雷不符合情况


            //没有人中雷--可能是六不中
            if (info.keySet().size() == 0) {
                //是否是六不中
                if (redType == 666) {
                    sgin = 1;
                    Out.debug("==============================================进入六不中==============================================");
                    //得到埋雷数
                    int maiNumber = thunderNumber.size();
                    //得到六不中的赔率
                    double current = magnification.get(maiNumber);
                    this.currentMagnification = current;
                    Out.debug("---------------当前倍率------进入六不中---------", current);
                    //全员赔钱
                    transportAmount = getTransportAmount(6, current);//得到每个人赔付的金额
                    Out.debug("-----------------六不中-----金额-------", transportAmount);
                }
            } else {//有人中雷--可能是单雷--连环雷
                sgin = 3;
                int leiNumber = info.keySet().size();//得到中雷数量
                Out.debug("得到中雷数量===>", leiNumber);


                //判断中雷情况---------------单雷--直接结算平均扣除中雷者金额
                if (thunderNumber.size() == 1) {//单雷
                    Out.debug("==============================================进入单雷==============================================");
                    sgin = 2;
                    double current = magnification.get(leiNumber);//得到当前雷的倍率
                    this.currentMagnification = current;
                    Out.debug("---------------当前倍率-------进入单雷--------", current);
                    long zongAmount = (long) (current * amount);
                    Out.debug("恭喜各位中了单雷");
                    Out.debug("当前红包==》", rpId, "当前中雷数==》", leiNumber, "得到当前的倍率", current, "---总金额==》", zongAmount);
                    transportAmount = getTransportAmount(leiNumber, current);//得到每个人赔付的金额
                    Out.debug("-----------------进入单雷-----中雷者每人赔付金额-------", transportAmount);
                } else {//------------------连环雷--直接结算平均扣除中雷者金额

                    //判断是不是符合连环雷的要求=======》中雷的前提条件--中雷数要>=埋雷数
                    if (leiNumber >= thunderNumber.size()) {
                        Set<Integer> thunderNumberSet = new HashSet<>();//将发包者选择的类list==》成set----用于下面比对
                        for (var lei : thunderNumber) {
                            thunderNumberSet.add(lei);
                        }
                        //将中雷者的雷存起来
                        Set<Integer> leiSet = new HashSet<>();
                        for (String userId : info.keySet()) {
                            leiSet.add(info.get(userId));//将当前雷返到雷set中---取重复
                        }

                        if (thunderNumberSet.equals(leiSet)) {//进入这里---这TM的几个逼是真的黑中雷
                            Out.debug("==============================================进入连环雷==============================================");
                            sgin = 2;//标识中雷
                            double current = magnification.get(leiSet.size());//得到当前雷的倍率
                            Out.debug("---------------当前倍率------进入连环雷---------", current);
                            this.currentMagnification = current;
                            long zongAmount = (long) (current * amount);
                            Out.debug("恭喜各位中了连环雷");
                            Out.debug("当前红包==》", rpId, "当前中雷数----卧槽连环雷........==》", leiNumber, "得到当前的倍率", current, "---总金额==》", zongAmount);
                            transportAmount = getTransportAmount(leiNumber, current);//得到每个人赔付的金额
                            Out.debug("-----------------进入连环雷-----中雷者每人赔付金额-------", transportAmount);
                        }
                    }
                }
            }

            long sendResultMoney = 0;
            if (sgin == 1) { //六不中
                for (var userId : rpResult.keySet()) {//全员扣钱
                    Out.debug("----------------全员扣钱------------------金额==》", transportAmount);
                    sendResultMoney += updateAmount(userId, transportAmount);
                }
            } else if (sgin == 2) {//单雷+连环雷
                for (var userId : info.keySet()) {//中雷者扣钱
                    Out.debug("----------------中雷者扣钱----------------金额==》", transportAmount);
                    sendResultMoney += updateAmount(userId, transportAmount);
                }
            } else if (sgin == 3) {
                Out.debug("-----------------雷是中了但不符合当前红包扣钱条件-----------------");
            } else {
                Out.debug("----------------恭喜各位没有任何人中雷------------------");
            }

            moneyRecode.getJSONObject(sendUserId).put("sendAmountback", balance);//发包者剩余的钱
            moneyRecode.getJSONObject(sendUserId).put("resultMoney", sendResultMoney);//发包者得到实际结算金额



            GamePushRedPackageByProto.PushRedPackage.Builder push = GamePushRedPackageByProto.PushRedPackage.newBuilder();
            push.setGameId(World.JINGQIANG);
            push.setRoomId(roomId);
            push.setRpId(rpId);
            if (sgin == 1 || sgin == 2) {//如果中雷向全房间广播中雷状态红包
                RpcMessage pushMsg = pushProto("", "push.RedPackage", push);
                jinQiangRoom.broadcast(pushMsg, "proxy");
            }
            for (var current : playerMap.values()) {//循环推送参与当前红包的玩家
                current.sendMsg(pushProto(current.userId, "push.RedPackageResult", push));
            }

            JSONArray array=new JSONArray();
            if (sgin == 1 || sgin == 2) {
                array.add(RpMassage.insertRpMessage(rpId, roomId, World.JINGQIANG, 2));//--------------------------------------------------
            }



            for (String userId : moneyRecode.keySet()) {
                JSONObject resultItem = moneyRecode.getJSONObject(userId);
                long total = 0;
                total += resultItem.getLongValue("sendAmount") + resultItem.getLongValue("sendAmountback") + resultItem.getLongValue("robMoney") + resultItem.getLongValue("resultMoney");
                long drawWater = getWinAmount(total,playerMap.get(userId));//手续费

                resultItem.put("drawWater", drawWater);

                long totalFreeze = 0;
                long finalMoney = total - drawWater;
                if (userId.equals(sendUserId)) {
                    totalFreeze = sendDeposit;
                } else {
                    totalFreeze = robDeposit;
                }
                resultItem.put("total", finalMoney);

                playerMap.get(userId).onSettlement(rpId, finalMoney + totalFreeze, -totalFreeze);
                array.add( Wallet.addMoneySql(playerMap.get(userId), finalMoney, 0,roomId));
                array.add(SettlementResult.makeResult(this, resultItem, userId, World.JINGQIANG));//插入流水账单
            }
            MysqlService.getInstance().executeMultipleAsyn(array);
            niuNiuJoinRedis();//这TM的一定要在remove之前入redis库
            jinQiangRoom.rpPackage.remove(rpId);

        } catch (Exception e) {
            Out.error(this.toString());
            e.printStackTrace();
        }
    }


    public long updateAmount(String userId, long transportAmount) {
        JSONObject recode = moneyRecode.getJSONObject(userId);
        //2.中雷者扣钱
        recode.put("resultMoney", -transportAmount);//扣钱
        return transportAmount;
    }

    //Redis 红包详情入库
    public void niuNiuJoinRedis() {
        Map<String, String> rpInfo = new HashMap<>();
        rpInfo.put("sendUserId", sendUserId);//发包者
        rpInfo.put("gameId", String.valueOf(World.JINGQIANG));//游戏Id
        rpInfo.put("roomId", String.valueOf(roomId));//房间Id
        rpInfo.put("RpId", rpId);//红包Id
        rpInfo.put("count", String.valueOf(count));//红包余数
        rpInfo.put("sumCount", String.valueOf(sumCount));//红包总个数
        rpInfo.put("amount", String.valueOf(amount));//红包金额
        rpInfo.put("balance", String.valueOf(balance));//红包余额
        rpInfo.put("moneyPieces", JSON.toJSONString(moneyPieces));//金额分配
        rpInfo.put("rpResult", String.valueOf(rpResult));//红包结果
        rpInfo.put("time", String.valueOf(time));//红包时间
        rpInfo.put("status", String.valueOf(status));//红包状态  0:发出 1:完成  2.撤回
        rpInfo.put("robDeposit", String.valueOf(robDeposit));//押金
        rpInfo.put("mediumMineNumber", String.valueOf(mediumMineNumber));//中雷数
        rpInfo.put("thunderNumber", String.valueOf(thunderNumber));//埋雷列表
        rpInfo.put("redType", String.valueOf(redType));//当前包的玩法类型  6单  66连环  666六不中
        rpInfo.put("rate", String.valueOf(currentMagnification));//当前赔率
        rpInfo.put("bonus", String.valueOf((long) currentMagnification * amount));//赔付金额
        R_REDPACKAGE_INFO.hmset(rpId, rpInfo);
    }


    //得到输的金额
    public long getTransportAmount(int count, double currentMagnification) {
        //输的金额 = 抢到的金额 * 倍率 /count
        return (long) (amount * currentMagnification) / count;
    }

    //得到红包类型
    public static int getType(int count, List<Integer> thunderNumber, int redType) {

        if (redType == 666) {
            return 666;
        }
        int thunderNum = thunderNumber.size();

        switch (count) {
            case 5:
                if (thunderNum > 1) {
                    return 55;
                } else {
                    return 5;
                }
            case 6:
                if (thunderNum > 1) {
                    return 66;
                } else {
                    return 6;
                }
            case 7:
                if (thunderNum > 1) {
                    return 77;
                } else {
                    return 7;
                }
            case 9:
                if (thunderNum > 1) {
                    return 99;
                } else {
                    return 9;
                }
            case 10:
                if (thunderNum > 2) {
                    return 10;
                }
        }
        return 1;
    }


}
